package de.wepner.texteditor.model;

import java.awt.event.ActionListener;
import java.util.HashMap;

import de.wepner.texteditor.command.Command;
import de.wepner.texteditor.command.NullCommand;
import de.wepner.texteditor.model.event.Event;
import de.wepner.texteditor.model.event.Event.EventAccessor;


/**
 * <p>Maps the {@link Command commands} to respective keys.</p>
 * 
 * @author Richard Wepner
 */
public class CommandMapping {
    
    private HashMap<String, ActionListener> commands = new HashMap<String, ActionListener>();
    /**
     * <p>Gets called when a command is assigned to a key.</p>
     */
    private final Event<CommandMapping, CommandChangeArguments> commandChangeEvent = new Event<CommandMapping, CommandChangeArguments>(
            this);
    
    /**
     * <p>The {@link EventAccessor} for the {@link #commandChangeEvent}</p>
     */
    public final Event<CommandMapping, CommandChangeArguments>.EventAccessor onCommandChanged = this.commandChangeEvent.accessor;
    
    /**
     * <p>Assigns the {@code command} to the {@code key}</p>
     * 
     * @param key the key, the command should be assigned to
     * @param command the command
     */
    public void setCommand(String key, ActionListener command) {
        if (key != null) {
            if (command != null) {
                this.commands.put(key, command);
                this.commandChangeEvent.fireEvent(new CommandChangeArguments(key, command));
            } else if (this.commands.containsKey(key)) {
                this.commands.remove(key);
                this.commandChangeEvent.fireEvent(new CommandChangeArguments(key, null));
            }
        }
    }
    
    /**
     * <p>Returns the command currently assigned to the {@code key}.</p>
     * <p>If there is no command assigned to the {@code key}, a {@link NullCommand} is instanciated,
     * assigned and returned.</p>
     * 
     * @param key the commands key
     * @return the assigned command
     */
    public ActionListener getCommand(String key) {
        if (this.commands.containsKey(key)) {
            return this.commands.get(key);
        } else {
            ActionListener command = new NullCommand();
            this.commands.put(key, command);
            return command;
        }
    }
    
    
    /**
     * <p>The event arguments for the {@link CommandMapping#commandChangeEvent}.</p>
     * <p>These contains the {@link #key}, the command was assigned to, as well as the
     * {@link #newCommand command} itself.</p>
     * 
     * @author Richard Wepner
     */
    public static class CommandChangeArguments {
        
        public final String key;
        public final ActionListener newCommand;
        
        public CommandChangeArguments(String key, ActionListener newCommand) {
            this.key = key;
            this.newCommand = newCommand;
        }
    }
}
